<template>
  <div class="image-upload">
    <!-- 上传区域 -->
    <el-upload
      ref="uploadRef"
      :action="uploadUrl"
      :http-request="autoUpload ? handleUpload : () => {}"
      :auto-upload="autoUpload"
      :before-upload="beforeUpload"
      :on-success="onSuccess"
      :on-error="onError"
      :on-progress="onProgress"
      :on-change="onChange"
      :multiple="multiple"
      :accept="accept"
      :limit="limit"
      :show-file-list="false"
      :disabled="disabled || (internalImageList.length >= limit)"
      v-bind="$attrs"
    >
      <div class="upload-grid">
        <!-- 已上传的图片预览 -->
        <div
          v-for="(image, index) in internalImageList"
          :key="image.uid || index"
          class="image-item"
          :class="{ 'is-uploading': image.status === 'uploading' }"
        >
          <div class="image-preview">
            <img :src="image.url" :alt="image.name" />
            
            <!-- 上传进度 -->
            <div v-if="image.status === 'uploading'" class="upload-progress">
              <el-progress
                type="circle"
                :percentage="image.percentage || 0"
                :width="50"
              />
            </div>
            
            <!-- 操作按钮 -->
            <div v-else class="image-actions">
              <div class="action-buttons">
                <el-button
                  circle
                  size="small"
                  type="primary"
                  @click="previewImage(image)"
                >
                  <el-icon><zoom-in /></el-icon>
                </el-button>
                <el-button
                  v-if="showDownload"
                  circle
                  size="small"
                  type="success"
                  @click="downloadImage(image)"
                >
                  <el-icon><download /></el-icon>
                </el-button>
                <el-button
                  circle
                  size="small"
                  type="danger"
                  @click="removeImage(index)"
                >
                  <el-icon><delete /></el-icon>
                </el-button>
              </div>
            </div>
            
            <!-- 错误状态 -->
            <div v-if="image.status === 'fail'" class="upload-error">
              <el-icon><circle-close /></el-icon>
              <span>上传失败</span>
            </div>
          </div>
          
          <!-- 图片信息 -->
          <div v-if="showImageInfo" class="image-info">
            <div class="image-name" :title="image.name">{{ image.name }}</div>
            <div class="image-size">{{ formatFileSize(image.size) }}</div>
          </div>
        </div>
        
        <!-- 上传按钮 -->
        <div
          v-if="internalImageList.length < limit"
          class="upload-placeholder"
          :class="{ 'is-disabled': disabled }"
        >
          <div class="upload-content">
            <el-icon class="upload-icon"><plus /></el-icon>
            <div class="upload-text">{{ placeholderText }}</div>
          </div>
        </div>
      </div>
      
      <template #tip v-if="tip">
        <div class="el-upload__tip">{{ tip }}</div>
      </template>
    </el-upload>

    <!-- 手动上传控制按钮 -->
    <div v-if="!autoUpload && internalImageList.length > 0" class="upload-controls">
      <el-button 
        type="primary" 
        :loading="uploading" 
        @click="startUpload"
        :disabled="!hasReadyImages"
      >
        <el-icon><upload-filled /></el-icon>
        {{ uploading ? '上传中...' : '开始上传' }}
      </el-button>
      <el-button 
        v-if="hasReadyImages" 
        @click="clearAllImages"
      >
        清空图片
      </el-button>
    </div>

    <!-- 图片预览对话框 -->
    <el-dialog
      v-model="previewVisible"
      :title="previewImage?.name || '图片预览'"
      width="80%"
      append-to-body
      class="image-preview-dialog"
    >
      <div class="preview-container">
        <img :src="currentPreviewImage?.url" :alt="currentPreviewImage?.name" />
      </div>
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="previewVisible = false">关闭</el-button>
          <el-button
            v-if="showDownload"
            type="primary"
            @click="downloadImage(currentPreviewImage!)"
          >
            下载图片
          </el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import {
  Plus,
  ZoomIn,
  Download,
  Delete,
  CircleClose,
  UploadFilled
} from '@element-plus/icons-vue'
import { fileApi } from '@/api/file'
import type { UploadFile, UploadRawFile, UploadRequestOptions } from 'element-plus'

interface ImageFile extends UploadFile {
  url?: string
}

interface ImageUploadProps {
  // 基础配置
  modelValue?: ImageFile[]
  multiple?: boolean
  limit?: number
  maxSize?: number // MB
  placeholderText?: string
  tip?: string
  disabled?: boolean
  
  // 业务配置
  businessType?: string
  businessKey?: string
  
  // 显示配置
  showImageInfo?: boolean
  showDownload?: boolean
  
  // 尺寸配置
  width?: number
  height?: number
  itemSize?: number // 预览项大小
  
  // 上传配置
  uploadUrl?: string
  autoUpload?: boolean
  
  // 图片限制
  minWidth?: number
  minHeight?: number
  maxWidth?: number
  maxHeight?: number
}

interface ImageUploadEmits {
  (e: 'update:modelValue', images: ImageFile[]): void
  (e: 'success', file: ImageFile, response: any): void
  (e: 'error', error: any, file: ImageFile): void
  (e: 'progress', event: any, file: ImageFile): void
  (e: 'remove', file: ImageFile, index: number): void
  (e: 'preview', file: ImageFile): void
}

const props = withDefaults(defineProps<ImageUploadProps>(), {
  multiple: true,
  limit: 9,
  maxSize: 10, // 10MB
  placeholderText: '上传图片',
  tip: '',
  disabled: false,
  businessType: 'image',
  businessKey: '',
  showImageInfo: true,
  showDownload: true,
  width: 0,
  height: 0,
  itemSize: 120,
  uploadUrl: '',
  autoUpload: true,
  minWidth: 0,
  minHeight: 0,
  maxWidth: 0,
  maxHeight: 0
})

const emit = defineEmits<ImageUploadEmits>()

const uploadRef = ref()
const internalImageList = ref<ImageFile[]>([])
const previewVisible = ref(false)
const currentPreviewImage = ref<ImageFile>()
const uploading = ref(false)

// 计算属性
const accept = computed(() => 'image/*')

const imageList = computed({
  get: () => props.modelValue || internalImageList.value,
  set: (val) => {
    internalImageList.value = val
    emit('update:modelValue', val)
  }
})

// 是否有待上传的图片
const hasReadyImages = computed(() => {
  return internalImageList.value.some(image => image.status === 'ready')
})

// 监听外部图片列表变化
watch(
  () => props.modelValue,
  (newVal) => {
    if (newVal) {
      internalImageList.value = [...newVal]
    }
  },
  { immediate: true }
)

// 图片上传前的检查
const beforeUpload = (rawFile: UploadRawFile): Promise<boolean> => {
  return new Promise((resolve) => {
    // 检查文件类型
    if (!rawFile.type.startsWith('image/')) {
      ElMessage.error('只能上传图片文件')
      resolve(false)
      return
    }
    
    // 检查文件大小
    if (rawFile.size > props.maxSize * 1024 * 1024) {
      ElMessage.error(`图片大小不能超过 ${props.maxSize}MB`)
      resolve(false)
      return
    }
    
    // 检查图片尺寸
    if (props.minWidth || props.minHeight || props.maxWidth || props.maxHeight) {
      const img = new Image()
      img.onload = () => {
        const { width, height } = img
        
        if (props.minWidth && width < props.minWidth) {
          ElMessage.error(`图片宽度不能小于 ${props.minWidth}px`)
          resolve(false)
          return
        }
        
        if (props.minHeight && height < props.minHeight) {
          ElMessage.error(`图片高度不能小于 ${props.minHeight}px`)
          resolve(false)
          return
        }
        
        if (props.maxWidth && width > props.maxWidth) {
          ElMessage.error(`图片宽度不能大于 ${props.maxWidth}px`)
          resolve(false)
          return
        }
        
        if (props.maxHeight && height > props.maxHeight) {
          ElMessage.error(`图片高度不能大于 ${props.maxHeight}px`)
          resolve(false)
          return
        }
        
        resolve(true)
      }
      
      img.onerror = () => {
        ElMessage.error('图片格式不正确')
        resolve(false)
      }
      
      img.src = URL.createObjectURL(rawFile)
    } else {
      resolve(true)
    }
  })
}

// 自定义上传方法
const handleUpload = async (options: UploadRequestOptions): Promise<void> => {
  // 创建预览URL
  const previewUrl = URL.createObjectURL(options.file)
  
  // 添加到列表中显示上传进度
  const imageFile: ImageFile = {
    name: options.file.name,
    size: options.file.size,
    status: 'uploading',
    percentage: 0,
    uid: Date.now() + Math.random(),
    url: previewUrl,
    raw: options.file
  }
  
  internalImageList.value.push(imageFile)
  
  // 更新进度
  const onProgress = (progressEvent: any) => {
    const percentage = Math.round((progressEvent.loaded * 100) / progressEvent.total)
    imageFile.percentage = percentage
    emit('progress', progressEvent, imageFile)
  }
  
  try {
    const response = await fileApi.uploadFile(
      options.file,
      props.businessType,
      props.businessKey
    )
    
    // 上传成功，更新文件信息
    imageFile.status = 'success'
    imageFile.response = response
    
    // 如果后端返回了图片URL，使用后端URL替换本地预览URL
    if (response.data?.downloadUrl) {
      URL.revokeObjectURL(imageFile.url!)
      imageFile.url = response.data.downloadUrl
    }
    
    emit('success', imageFile, response)
    options.onSuccess(response, options.file)
    
  } catch (error: any) {
    // 上传失败
    imageFile.status = 'fail'
    emit('error', error, imageFile)
    options.onError(error)
  }
}

// 上传成功回调
const onSuccess = (response: any, file: UploadFile) => {
  // 已在 handleUpload 中处理
}

// 上传失败回调
const onError = (error: any, file: UploadFile) => {
  ElMessage.error(error?.message || '图片上传失败')
}

// 上传进度回调
const onProgress = (event: any, file: UploadFile) => {
  // 已在 handleUpload 中处理
}

// 文件状态变化回调（手动上传模式）
const onChange = (file: UploadFile, fileList: UploadFile[]) => {
  if (!props.autoUpload) {
    // 手动上传模式，将文件状态设置为ready并生成预览URL
    file.status = 'ready'
    
    // 为图片生成预览URL
    if (file.raw && file.raw.type.startsWith('image/')) {
      (file as ImageFile).url = URL.createObjectURL(file.raw)
    }
    
    internalImageList.value = [...fileList as ImageFile[]]
    emit('update:modelValue', internalImageList.value)
  }
}

// 开始手动上传
const startUpload = async () => {
  if (uploading.value) return
  
  uploading.value = true
  const readyImages = internalImageList.value.filter(image => image.status === 'ready')
  
  for (const image of readyImages) {
    try {
      image.status = 'uploading'
      image.percentage = 0
      
      const response = await fileApi.uploadFile(
        image.raw as File,
        props.businessType,
        props.businessKey,
        (progressEvent) => {
          // 更新上传进度
          if (progressEvent.lengthComputable) {
            image.percentage = Math.round((progressEvent.loaded * 100) / progressEvent.total)
          }
        }
      )
      
      image.status = 'success'
      image.response = response
      image.percentage = 100
      
      // 如果后端返回了图片URL，使用后端URL替换本地预览URL
      if (response.data?.downloadUrl) {
        URL.revokeObjectURL(image.url!)
        image.url = response.data.downloadUrl
      }
      
      emit('success', image, response)
      
    } catch (error: any) {
      image.status = 'fail'
      emit('error', error, image)
    }
  }
  
  uploading.value = false
}

// 清空所有图片
const clearAllImages = () => {
  // 清理所有本地URL
  internalImageList.value.forEach(image => {
    if (image.url && image.url.startsWith('blob:')) {
      URL.revokeObjectURL(image.url)
    }
  })
  
  internalImageList.value = []
  emit('update:modelValue', [])
  uploadRef.value?.clearFiles()
}

// 预览图片
const previewImage = (image: ImageFile) => {
  currentPreviewImage.value = image
  previewVisible.value = true
  emit('preview', image)
}

// 下载图片
const downloadImage = async (image: ImageFile) => {
  if (!image.response?.data?.fileId) {
    ElMessage.error('图片信息不完整，无法下载')
    return
  }
  
  try {
    await fileApi.downloadFile(image.response.data.fileId)
  } catch (error: any) {
    ElMessage.error(error?.message || '下载失败')
  }
}

// 移除图片
const removeImage = async (index: number) => {
  const image = internalImageList.value[index]
  
  try {
    await ElMessageBox.confirm('确定要删除该图片吗？', '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    })
    
    // 如果图片已上传成功，调用删除API
    if (image.response?.success && image.response?.data?.fileId) {
      try {
        await fileApi.deleteFile(image.response.data.fileId)
      } catch (error) {
        console.warn('删除服务器图片失败:', error)
      }
    }
    
    // 清理本地预览URL
    if (image.url && image.url.startsWith('blob:')) {
      URL.revokeObjectURL(image.url)
    }
    
    internalImageList.value.splice(index, 1)
    emit('remove', image, index)
    
  } catch {
    // 用户取消删除
  }
}

// 格式化文件大小
const formatFileSize = (size?: number): string => {
  if (!size) return '0 B'
  
  const units = ['B', 'KB', 'MB', 'GB']
  let unitIndex = 0
  let fileSize = size
  
  while (fileSize >= 1024 && unitIndex < units.length - 1) {
    fileSize /= 1024
    unitIndex++
  }
  
  return `${fileSize.toFixed(1)} ${units[unitIndex]}`
}

// 清空图片列表
const clearImages = () => {
  // 清理所有本地预览URL
  internalImageList.value.forEach(image => {
    if (image.url && image.url.startsWith('blob:')) {
      URL.revokeObjectURL(image.url)
    }
  })
  
  uploadRef.value?.clearFiles()
  internalImageList.value = []
  emit('update:modelValue', [])
}

// 暴露方法给父组件
defineExpose({
  clearImages,
  uploadRef
})
</script>

<style scoped>
/* 动态样式 - 使用 CSS 变量绑定，保留在组件内 */
.upload-grid {
  grid-template-columns: repeat(auto-fill, minmax(v-bind('itemSize + "px"'), 1fr));
}

.image-item {
  width: v-bind('itemSize + "px"');
  height: v-bind('itemSize + "px"');
}

.upload-placeholder {
  width: v-bind('itemSize + "px"');
  height: v-bind('itemSize + "px"');
}

/* 其他样式已迁移到 @/styles/modules/file.scss */
</style>
